package cn.anlab.anappframe.net.sub;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Queue;

import android.util.Log;

/**
 * 客户端连接类
 * 
 * @version 1.0
 * @author Stan Rong 2012-3-2
 */
public class NIOClient implements IClient, Runnable {

	private String address;
	private int port;

	private static Selector selector;
	private static final int PREFIX_BUFFER_LENGTH = 4;			//报文前缀的长度
	
	private SocketChannel channel;
	
	private IDataHandler dataHandler;
	
	public NIOClient(String address, int port) {
		this.address = address;
		this.port = port;
	}
	
	/**
	 * 连接
	 * @throws IOException
	 */
	public void connect() throws IOException {
		// 开启selector,并建立socket到指定端口的连接
		if (selector == null)
			selector = Selector.open();
		channel = SocketChannel.open();
		channel.configureBlocking(false);
		channel.connect(new InetSocketAddress(address, port));
		channel.register(selector, SelectionKey.OP_CONNECT);
		// 进行信息读取
		for (;;) {
			selector.select();
			Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
			while (keyIterator.hasNext()) {
				SelectionKey key = keyIterator.next();
				keyIterator.remove();
				// 连接事件
				if (key.isConnectable()) {
					Log.d("anlog", "key.isConnectable()");
					SocketChannel socketChannel = (SocketChannel) key.channel();
					if (socketChannel.isConnectionPending())
						socketChannel.finishConnect();
//					socketChannel.write(ByteBuffer.wrap("aaabbb".getBytes()));		//连接成功，发送认证信息
					socketChannel.register(selector, SelectionKey.OP_READ);
				}
				// 读事件
				if (key.isReadable()) {
					Log.d("anlog", "key.isReadable()");
					SocketChannel socketChannel = (SocketChannel) key.channel();
					if (!socketChannel.isConnected()) {
						Log.e("anlog", "!socketChannel.isConnected()");
						//TODO
					}
					//获取报文的长度
					ByteBuffer prefixBuff = ByteBuffer.allocate(PREFIX_BUFFER_LENGTH);
					int readSize0 = socketChannel.read(prefixBuff);
					if (readSize0 < PREFIX_BUFFER_LENGTH) {
						key.cancel();
					}
					prefixBuff.flip();
					int length = prefixBuff.asIntBuffer().get();
					prefixBuff.clear();
					//读取报文正文内容
					ByteBuffer byteBuffer = ByteBuffer.allocate(length);
					int readSize = socketChannel.read(byteBuffer);
					if(readSize != length) {
						System.out.println("报文长度不对！");
						//TODO
					}
					//处理响应
					byteBuffer.flip();
					byte[] bytes = byteBuffer.array();
					dataHandler.onDataReceived(bytes);
					byteBuffer.clear();
				}
			}
		}
	}
	
	/**
	 * 断开连接
	 * @throws IOException
	 */
	public void disconnect() throws IOException {
		if(channel != null) {
			channel.close();
			channel = null;
		}
	}
	
	/**
	 * 判断是否已经连接
	 * @return
	 */
	public boolean isConnected() {
		if(channel != null) {
			return channel.isConnected();
		}
		return false;
	}
	
	/**
	 * 发送数据
	 */
	public void send(byte[] bytes) throws IOException {
		int length = 4 + bytes.length;
		ByteBuffer buff = ByteBuffer.allocate(length);
		buff.putInt(length);
		buff.put(bytes);
		buff.flip();
		channel.write(buff);
	}
	
	@Override
	public void run() {
		try {
			connect();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void setDataHandler(IDataHandler dataHandler) {
		this.dataHandler = dataHandler;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public void setPort(int port) {
		this.port = port;
	}


}